{
 "metadata": {
  "signature": "sha256:1db0212221a85e630b4909a49684e2997182753ef2900cdc2c9c1d5292e45c5c"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Matplotlib: animations\n",
      "======================================================================\n",
      "\n",
      "***Note:*** Some of the matplotlib code in this cookbook entry may be\n",
      "deprecated or obsolete. For example, the file **anim.py** mentioned\n",
      "below no longer exists in matplotlib. Examples of animation in\n",
      "matplotlib are at\n",
      "<http://matplotlib.sourceforge.net/examples/animation/index.html>, and\n",
      "the main animation API documentation is\n",
      "<http://matplotlib.sourceforge.net/api/animation_api.html>.\n",
      "\n",
      "* * * * *\n",
      "\n",
      "matplotlib supports animated plots, and provides a number of demos. An\n",
      "important question when considering whether to use matplotlib for\n",
      "animation is what kind of speed you need. matplotlib is not the fastest\n",
      "plotting library in the west, and may be too slow for some animation\n",
      "applications. Nonetheless, it is fast enough for many if not most, and\n",
      "this tutorial is geared to showing you how to make it fast enough for\n",
      "you. In particular, the section \\*Animating selected plot elements\\*\n",
      "shows you how to get top speed out of matplotlib animations.\n",
      "\n",
      "<TableOfContents>\n",
      "\n",
      "Performance\n",
      "-----------\n",
      "\n",
      "matplotlib supports 5 different graphical user interfaces (GTK, WX, Qt,\n",
      "Tkinter, FLTK) and for some of those GUIs, there are various ways to\n",
      "draw to the canvas. For example, for GTK, you can use native [GDK\n",
      "drawing](http://www.pygtk.org/pygtk2reference/class-gdkdrawable.html),\n",
      "[antigrain](http://antigrain.com), or\n",
      "[cairo](http://cairographics.org/). A GUI toolkit combined with some\n",
      "method of drawing comprises a\n",
      "[backend](http://matplotlib.sourceforge.net/backends.html). For example,\n",
      "drawing to a GTK canvas with the antigrain drawing toolkit is called the\n",
      "GTKAgg backend. This is important because different backends have\n",
      "different performance characteristics, and the difference can be\n",
      "considerable.\n",
      "\n",
      "When considering performance, the typical measure is frames per second.\n",
      "Television is 30 frames per second, and for many application if you can\n",
      "get 10 or more frames per second the animation is smooth enough to \"look\n",
      "good\". Monitors refresh at 75-80 frames per second typically, and so\n",
      "this is an upper limit for performance. Any faster is probably wasted\n",
      "CPU cycles.\n",
      "\n",
      "Here are some numbers for the animated script\n",
      "[anim.py](http://matplotlib.sf.net/examples/anim.py), which simply\n",
      "updates a sine wave on various backends, run under linux on a 3GHz\n",
      "Pentium IV. To profile a script under different backends, you can use\n",
      "the \"GUI neutral\" animation technique described below and then run it\n",
      "with the flag, as in:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "> python anim.py -dWX\n",
      "> python anim.py -dGTKAgg"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Here are the results. Note that these should be interpreted cautiously,\n",
      "because some GUIs might call a drawing operation in a separate thread\n",
      "and return before it is complete, or drop a drawing operation while one\n",
      "is in the queue. The most important assessment is qualitative."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "Backend  Frames/second\n",
      " GTK         43   \n",
      " GTKAgg      36 \n",
      " TkAgg       20 \n",
      " WX          11\n",
      " WXAgg       27"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "GUI neutral animation in pylab\n",
      "------------------------------\n",
      "\n",
      "The pylab interface supports animation that does not depend on a\n",
      "specific GUI toolkit. This is not recommended for production use, but is\n",
      "often a good way to make a quick-and-dirty, throw away animation. After\n",
      "importing pylab, you need to turn interaction on with the\n",
      "[<http://matplotlib.sf.net/matplotlib.pylab.html>\\#-ion ion] command.\n",
      "You can then force a draw at any time with\n",
      "[<http://matplotlib.sf.net/matplotlib.pylab.html>\\#-draw draw]. In\n",
      "interactive mode, a new draw command is issued after each pylab command,\n",
      "and you can also temporarily turn off this behavior for a block of\n",
      "plotting commands in which you do not want an update with the\n",
      "[<http://matplotlib.sf.net/matplotlib.pylab.html>\\#-ioff ioff] commands.\n",
      "This is described in more detail on the\n",
      "[interactive](http://matplotlib.sf.net/interactive.html) page.\n",
      "\n",
      "Here is the anim.py script that was used to generate the profiling\n",
      "numbers across backends in the table above"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from pylab import *\n",
      "import time\n",
      "\n",
      "ion()  \n",
      "\n",
      "tstart = time.time()               # for profiling\n",
      "x = arange(0,2*pi,0.01)            # x-array\n",
      "line, = plot(x,sin(x))\n",
      "for i in arange(1,200):\n",
      "    line.set_ydata(sin(x+i/10.0))  # update the data\n",
      "    draw()                         # redraw the canvas\n",
      "\n",
      "print 'FPS:' , 200/(time.time()-tstart)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Note the technique of creating a line with the call to\n",
      "[<http://matplotlib.sf.net/matplotlib.pylab.html>\\#-plot plot]:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "line, = plot(x,sin(x))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "and then setting its data with the set\\_ydata method and calling draw:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "line.set_ydata(sin(x+i/10.0))  # update the data\n",
      "draw()                         # redraw the canvas"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "This can be much faster than clearing the axes and/or creating new\n",
      "objects for each plot command.\n",
      "\n",
      "To animate a pcolor plot use:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "p = pcolor(XI,YI,C[0])\n",
      "\n",
      "for i in range(1,len(C)):\n",
      "  p.set_array(C[i,0:-1,0:-1].ravel())\n",
      "  p.autoscale()\n",
      "  draw()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "This assumes C is a 3D array where the first dimension is time and that\n",
      "XI,YI and C[i,:,:] have the same shape. If C[i,:,:] is one row and one\n",
      "column smaller simply use C.ravel().\n",
      "\n",
      "Using the GUI timers or idle handlers\n",
      "-------------------------------------\n",
      "\n",
      "If you are doing production code or anything semi-serious, you are\n",
      "advised to use the GUI event handling specific to your toolkit for\n",
      "animation, because this will give you more control over your animation\n",
      "than matplotlib can provide through the GUI neutral pylab interface to\n",
      "animation. How you do this depends on your toolkit, but there are\n",
      "examples for several of the backends in the matplotlib examples\n",
      "directory, eg,\n",
      "[anim\\_tk.py](http://matplotlib.sf.net/examples/anim_tk.py) for Tkinter,\n",
      "[dynamic\\_image\\_gtkagg.py](http://matplotlib.sf.net/examples/dynamic_image_gtkagg.py)\n",
      "for GTKAgg and\n",
      "[dynamic\\_image\\_wxagg.py](http://matplotlib.sf.net/examples/dynamic_image_wxagg.py)\n",
      "for WXAgg.\n",
      "\n",
      "The basic idea is to create your figure and a callback function that\n",
      "updates your figure. You then pass that callback to the GUI idle handler\n",
      "or timer. A simple example in GTK looks like"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def callback(*args):  \n",
      "   line.set_ydata(get_next_plot())\n",
      "   canvas.draw()  # or simply \"draw\" in pylab\n",
      "\n",
      "gtk.idle_add(callback)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "A simple example in WX or WXAgg looks like"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def callback(*args):  \n",
      "   line.set_ydata(get_next_plot())\n",
      "   canvas.draw()\n",
      "   wx.WakeUpIdle() # ensure that the idle event keeps firing\n",
      "\n",
      "wx.EVT_IDLE(wx.GetApp(), callback)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Animating selected plot elements\n",
      "--------------------------------\n",
      "\n",
      "One limitation of the methods presented above is that all figure\n",
      "elements are redrawn with every call to draw, but we are only updating a\n",
      "single element. Often what we want to do is draw a background, and\n",
      "animate just one or two elements on top of it. As of matplotlib-0.87,\n",
      "GTKAgg, !TkAgg, WXAgg, and FLTKAgg support the methods discussed here.\n",
      "\n",
      "The basic idea is to set the 'animated' property of the Artist you want\n",
      "to animate (all figure elements from Figure to Axes to Line2D to Text\n",
      "derive from the base class\n",
      "[Artist](http://matplotlib.sf.net/matplotlib.artist.html)). Then, when\n",
      "the standard canvas draw operation is called, all the artists except the\n",
      "animated one will be drawn. You can then use the method to copy a\n",
      "rectangular region (eg the axes bounding box) into a a pixel buffer. In\n",
      "animation, you restore the background with , and then call to draw your\n",
      "animated artist onto the clean background, and to blit the updated axes\n",
      "rectangle to the figure. When I run the example below in the same\n",
      "environment that produced 36 FPS for GTKAgg above, I measure 327 FPS\n",
      "with the techniques below. See the caveats on performance numbers\n",
      "mentioned above. Suffice it to say, quantitatively and qualitiatively it\n",
      "is much faster."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import sys\n",
      "import gtk, gobject\n",
      "import pylab as p\n",
      "import matplotlib.numerix as nx\n",
      "import time\n",
      "\n",
      "ax = p.subplot(111)\n",
      "canvas = ax.figure.canvas\n",
      "\n",
      "# for profiling\n",
      "tstart = time.time()\n",
      "\n",
      "# create the initial line\n",
      "x = nx.arange(0,2*nx.pi,0.01)\n",
      "line, = p.plot(x, nx.sin(x), animated=True)\n",
      "\n",
      "# save the clean slate background -- everything but the animated line\n",
      "# is drawn and saved in the pixel buffer background\n",
      "background = canvas.copy_from_bbox(ax.bbox)\n",
      "\n",
      "def update_line(*args):\n",
      "    # restore the clean slate background\n",
      "    canvas.restore_region(background)\n",
      "    # update the data\n",
      "    line.set_ydata(nx.sin(x+update_line.cnt/10.0))  \n",
      "    # just draw the animated artist\n",
      "    ax.draw_artist(line)\n",
      "    # just redraw the axes rectangle\n",
      "    canvas.blit(ax.bbox) \n",
      "\n",
      "    if update_line.cnt==50:\n",
      "        # print the timing info and quit\n",
      "        print 'FPS:' , update_line.cnt/(time.time()-tstart)\n",
      "        sys.exit()\n",
      "\n",
      "    update_line.cnt += 1\n",
      "    return True\n",
      "update_line.cnt = 0\n",
      "\n",
      "gobject.idle_add(update_line)\n",
      "p.show()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Example: cursoring\n",
      "------------------\n",
      "\n",
      "matplotlib 0.83.2 introduced a cursor class which can utilize these blit\n",
      "methods for no lag cursoring. The class takes a argument in the\n",
      "constructor. For backends that support the new API (GTKAgg) set :"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from matplotlib.widgets import Cursor\n",
      "import pylab\n",
      "\n",
      "fig = pylab.figure(figsize=(8,6))\n",
      "ax = fig.add_axes([0.075, 0.25, 0.9, 0.725], axisbg='#FFFFCC')\n",
      "\n",
      "x,y = 4*(pylab.rand(2,100)-.5)\n",
      "ax.plot(x,y,'o')\n",
      "ax.set_xlim(-2,2)\n",
      "ax.set_ylim(-2,2)\n",
      "\n",
      "# set useblit = True on gtkagg for enhanced performance    \n",
      "cursor = Cursor(ax, useblit=True, color='red', linewidth=2 )\n",
      "\n",
      "pylab.show()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The 'blit' animation methods\n",
      "----------------------------\n",
      "\n",
      "As noted above, only the GTKAgg supports the methods above to to the\n",
      "animations of selected actors. The following are needed\n",
      "\n",
      "### Figure canvas methods\n",
      "\n",
      "`*\u00a0``\u00a0-\u00a0copy\u00a0the\u00a0region\u00a0in\u00a0ax.bbox\u00a0into\u00a0a\u00a0pixel\u00a0buffer\u00a0and\u00a0return\u00a0it\u00a0in\u00a0an\u00a0object\u00a0type\u00a0of\u00a0your\u00a0choosing.\u00a0\u00a0bbox\u00a0is\u00a0a\u00a0matplotlib\u00a0BBox\u00a0instance\u00a0from\u00a0the\u00a0`[`transforms`\n",
      "`module`](http://matplotlib.sf.net/transforms.html)`.\u00a0``\u00a0is\u00a0not\u00a0used\u00a0by\u00a0the\u00a0matplotlib\u00a0frontend,\u00a0but\u00a0it\u00a0stores\u00a0it\u00a0and\u00a0passes\u00a0it\u00a0back\u00a0to\u00a0the\u00a0backend\u00a0in\u00a0the\u00a0``\u00a0method.\u00a0You\u00a0will\u00a0probably\u00a0want\u00a0to\u00a0store\u00a0not\u00a0only\u00a0the\u00a0pixel\u00a0buffer\u00a0but\u00a0the\u00a0rectangular\u00a0region\u00a0of\u00a0the\u00a0canvas\u00a0from\u00a0whence\u00a0it\u00a0came\u00a0in\u00a0the\u00a0background\u00a0object.`\n",
      "\n",
      "`*\u00a0``\u00a0-\u00a0restore\u00a0the\u00a0region\u00a0copied\u00a0above\u00a0to\u00a0the\u00a0canvas.\u00a0\u00a0`\n",
      "\n",
      "`*\u00a0``\u00a0-\u00a0transfer\u00a0the\u00a0pixel\u00a0buffer\u00a0in\u00a0region\u00a0bounded\u00a0by\u00a0bbox\u00a0to\u00a0the\u00a0canvas.`\n",
      "\n",
      "For \\*Agg backends, there is no need to implement the first two as Agg\n",
      "will do all the work ( defines them). Thus you only need to be able to\n",
      "blit the agg buffer from a selected rectangle. One thing that might make\n",
      "this easier for backends using string methods to transfer the agg pixel\n",
      "buffer to their respective canvas is to define a method in agg. If you\n",
      "are working on this and need help, please contact the [matplotlib-devel\n",
      "list](http://sourceforge.net/mailarchive/forum.php?forum_id=36187).\n",
      "\n",
      "Once all/most of the backends have implemented these methods, the\n",
      "matplotlib front end can do all the work of managing the\n",
      "background/restore/blit opertations, and userland animated code can look\n",
      "like"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "line, = plot(something, animated=True)\n",
      "draw()   \n",
      "def callback(*args):\n",
      "    line.set_ydata(somedata)\n",
      "    ax.draw_animated()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "and the rest will happen automagically.  Since some backends '''do not''' currently implement \n",
      "the required methods, I am making them available to the users to manage themselves but\n",
      "am not assuming them in the axes drawing code."
     ]
    }
   ],
   "metadata": {}
  }
 ]
}